package cn.com.dragonsoftbravo.utils.azure;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.springframework.web.multipart.MultipartFile;

import com.google.gson.Gson;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlobDirectory;
import com.microsoft.azure.storage.blob.CloudBlockBlob;
import com.microsoft.azure.storage.blob.ListBlobItem;

import cn.com.dragonsoftbravo.utils.IOCloseUtils;
import cn.com.dragonsoftbravo.utils.azure.factory.BlobContainerFactory;
import cn.com.dragonsoftbravo.utils.azure.model.UploadWASResult;
import cn.com.dragonsoftbravo.utils.azure.model.UserValidationResult;
import cn.com.dragonsoftbravo.utils.azure.utils.ExifUtils;
import cn.com.dragonsoftbravo.utils.azure.utils.MetadataUtils;
import cn.com.dragonsoftbravo.utils.azure.was.WASService;

public class BlobService {

	private static Logger log = Logger.getLogger(BlobService.class);

	public static void cleanAllTheUnapprovedImages() {
		try {

			CloudBlobContainer imageContainer = BlobContainerFactory.getContainer();
			Iterable<ListBlobItem> lst = imageContainer.listBlobs(null, true, null, null, null);
			for (ListBlobItem item : lst) {
				if (item instanceof CloudBlockBlob) {
					CloudBlockBlob blob = (CloudBlockBlob) item;
					blob.deleteIfExists();
				}
			}

		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
		}
	}

	public static String executeCompleteUpload(MultipartFile imagefile, String campaignId, int fileType, String userToken, int userTokenType,
			String uploadToken, int uploadTokenType, String userId) throws Exception {

		InputStream is = imagefile.getInputStream();
		BufferedInputStream bis = new BufferedInputStream(is);

		if (fileType == 0) {
			bis.mark(Integer.MAX_VALUE);
		}

		String fileName = imagefile.getOriginalFilename();
		String extName = fileName.substring(fileName.lastIndexOf("."));

		String fileRef = getFileReference() + extName;

		try {
			UserValidationResult validationResult = WASService.validateToken(userToken, userTokenType, userId);

			// validation fail
			if (!validationResult.getCode().equals(AzureConstants.UPLOAD_STATUS_NORMAL)) {
				log.error(validationResult.getMessage());
				return validationResult.toString();
			}

			CloudBlobDirectory directory = BlobContainerFactory.getDirectoryName(campaignId, fileType);
			final CloudBlockBlob blob = directory.getBlockBlobReference(fileRef);

			long fileLength = bis.available();

			MetadataUtils.setMetaData(blob, AzureConstants.METEDATA_IMAGE_STATUS, AzureConstants.IMAGE_STATUS_NEW);

			// log.info("Server: Start uploading the original image. Image blob
			// name is : " + fileRef);
			// blob.upload(bis, fileLength);
			// log.info("Server: Finish uploading the original image. Image blob
			// name is : " + fileRef);

			Map<String, String> exifs = new HashMap<String, String>();

			UploadProcess.process(fileRef, bis, fileType, "Tomcat", campaignId, extName);

			if (fileType == 0) {
				bis.reset();
				exifs = ExifUtils.getExifs(bis, fileRef);
			}

			UploadWASResult uploadResult = WASService.uploadToWas(campaignId, fileType, uploadToken, uploadTokenType, userId, fileLength, blob,
					exifs);

			if (!uploadResult.getCode().equals(AzureConstants.UPLOAD_STATUS_NORMAL)) {
				rollbackUpload(blob);
			}

			return uploadResult.toString();

		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
			return getSysError(e.getMessage());
		} finally {
			IOCloseUtils.close(bis);
			IOCloseUtils.close(is);
		}

	}

	public static String uploadToContainer(InputStream is, String fullBlobName) {
		try {
			CloudBlobContainer container = BlobContainerFactory.getContainer();
			CloudBlockBlob blob = container.getBlockBlobReference(fullBlobName);
			long fileLength = is.available();
			blob.upload(is, fileLength);
			return fullBlobName;
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
			return null;
		}
	}

	public static String uploadThumbnail(InputStream is, CloudBlobDirectory directory, String extName) {
		try {

			String reference = getFileReference() + extName;
			CloudBlockBlob blob = directory.getBlockBlobReference(reference);
			long fileLength = is.available();
			blob.upload(is, fileLength);
			return blob.getName();
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
			return null;
		}
	}

	public static void approve(String blobName) {

		try {
			CloudBlobContainer imageContainer = BlobContainerFactory.getContainer();
			CloudBlockBlob blob = imageContainer.getBlockBlobReference(blobName);
			MetadataUtils.setMetaData(blob, AzureConstants.METEDATA_IMAGE_STATUS, AzureConstants.IMAGE_STATUS_ARRPOVED);
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
		}
	}

	public static void reject(String blobName) {

		try {
			CloudBlobContainer imageContainer = BlobContainerFactory.getContainer();
			CloudBlockBlob blob = imageContainer.getBlockBlobReference(blobName);
			MetadataUtils.setMetaData(blob, AzureConstants.METEDATA_IMAGE_STATUS, AzureConstants.IMAGE_STATUS_REJECTED);
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
		}
	}

	public static boolean delete(String blobName) {
		try {
			CloudBlobContainer imageContainer = BlobContainerFactory.getContainer();
			CloudBlockBlob blob = imageContainer.getBlockBlobReference(blobName);
			if (blob.exists()) {
				MetadataUtils.setMetaData(blob, AzureConstants.METEDATA_IMAGE_STATUS, AzureConstants.IMAGE_STATUS_REMOVED);
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
			return false;
		}

	}

	public static List<CloudBlockBlob> getImageList() {

		try {
			CloudBlobContainer container = BlobContainerFactory.getContainer();
			List<CloudBlockBlob> blobs = new ArrayList<CloudBlockBlob>();
			Iterable<ListBlobItem> lst = container.listBlobs(null, true, null, null, null);

			for (ListBlobItem item : lst) {
				if (item instanceof CloudBlockBlob) {
					CloudBlockBlob blob = (CloudBlockBlob) item;
					blob.downloadAttributes();
					blobs.add(blob);
				}
			}

			return blobs;

		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
		}

		return null;

	}

	public static List<CloudBlockBlob> getThumbnailList() {

		try {
			CloudBlobDirectory originalDirectory = BlobContainerFactory.getThumbnailDirectory();

			List<CloudBlockBlob> blobs = new ArrayList<CloudBlockBlob>();

			Iterable<ListBlobItem> lst = originalDirectory.listBlobs();

			for (ListBlobItem item : lst) {
				CloudBlockBlob blob = (CloudBlockBlob) item;
				blob.downloadAttributes();
				blobs.add(blob);
			}

			return blobs;

		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
		}

		return null;

	}

	public static void downloadImage(String fullBlobName, OutputStream out) {
		try {
			CloudBlobContainer imageContainer = BlobContainerFactory.getContainer();
			CloudBlockBlob blob = imageContainer.getBlockBlobReference(fullBlobName);

			if (blob.exists()) {
				if (!blob.getMetadata().containsKey(AzureConstants.METEDATA_IMAGE_STATUS)
						|| !MetadataUtils.getMetaData(blob, AzureConstants.METEDATA_IMAGE_STATUS).equals(AzureConstants.IMAGE_STATUS_REMOVED)) {
					blob.download(out);
				}
			}

		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			IOCloseUtils.close(out);
		}
	}

	private static void rollbackUpload(CloudBlockBlob blob) throws Exception {
		// remove the file
		CloudBlobContainer imageContainer = BlobContainerFactory.getContainer();
		imageContainer.getBlockBlobReference(blob.getMetadata().get(AzureConstants.THUMBNAIL_IMAGE_BLOB_NAME)).deleteIfExists();
		imageContainer.getBlockBlobReference(blob.getMetadata().get(AzureConstants.THUMBNAIL_IMAGE_BLOB_NAME2)).deleteIfExists();
		blob.deleteIfExists();
	}

	private static String getSysError(String errMsg) {

		log.error(errMsg);

		UploadWASResult rr = new UploadWASResult();
		rr.setCode(AzureConstants.UPLOAD_STATUS_SYS_ERR);
		rr.setMessage(errMsg);

		String returnValue = new Gson().toJson(rr, UploadWASResult.class);
		return returnValue;
	}

	public static String getFileReference() {
		return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
	}

}
